package com.jof.framework.jdbc;

import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.Array;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.NClob;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.Ref;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.RowId;
import java.sql.SQLException;
import java.sql.SQLXML;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Calendar;

/**
 * 预处理语句
 * @author Jonathan
 *
 */
public class HOPPraparedStatement extends HOPStatement implements PreparedStatement {
	protected static final String READER = "READER";
	protected static final String INPUTSTREAM = "INPUTSTREAM";
	private PreparedStatement targetStatement;
	public HOPPraparedStatement(HOPConnection connection,PreparedStatement targetStatement,String sql, HOPJdbcConfiguration configuration) {
		super(connection,targetStatement,configuration);
		this.targetStatement = targetStatement;
		this.sql = new StringBuilder(sql);
	}

	
	public ResultSet executeQuery() throws SQLException {
		return doProfile(new ProfilePreparedStatementCallable<ResultSet>() {
			
			public ResultSet run(PreparedStatement statement) throws SQLException {
				return statement.executeQuery();
			}
		});
	}

	
	public int executeUpdate() throws SQLException {
		return doProfile(new ProfilePreparedStatementCallable<Integer>() {
			
			public Integer run(PreparedStatement statement) throws SQLException {
				return targetStatement.executeUpdate();
			}
		});
	}

	
	public void setNull(int parameterIndex, int sqlType) throws SQLException {
		targetStatement.setNull(parameterIndex, sqlType);
	}

	
	public void setBoolean(int parameterIndex, boolean x) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setBoolean(parameterIndex, x);
	}

	
	public void setByte(int parameterIndex, byte x) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setByte(parameterIndex, x);
	}

	
	public void setShort(int parameterIndex, short x) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setShort(parameterIndex, x);
	}

	
	public void setInt(int parameterIndex, int x) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setInt(parameterIndex, x);
	}

	
	public void setLong(int parameterIndex, long x) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setLong(parameterIndex, x);
	}

	
	public void setFloat(int parameterIndex, float x) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setFloat(parameterIndex, x);
	}

	
	public void setDouble(int parameterIndex, double x) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setDouble(parameterIndex, x);
	}

	
	public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setBigDecimal(parameterIndex, x);
	}

	
	public void setString(int parameterIndex, String x) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setString(parameterIndex, x);
	}

	
	public void setBytes(int parameterIndex, byte[] x) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setBytes(parameterIndex, x);
	}

	
	public void setDate(int parameterIndex, Date x) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setDate(parameterIndex, x);
	}

	
	public void setTime(int parameterIndex, Time x) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setTime(parameterIndex, x);
	}

	
	public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setTimestamp(parameterIndex, x);
	}

	
	public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setAsciiStream(parameterIndex, x, length);
	}

	@SuppressWarnings("deprecation")
	
	public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setUnicodeStream(parameterIndex, x, length);
	}

	
	public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setBinaryStream(parameterIndex, x, length);
	}

	
	public void clearParameters() throws SQLException {
		targetStatement.clearParameters();
	}

	
	public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setObject(parameterIndex, x, targetSqlType);
	}

	
	public void setObject(int parameterIndex, Object x) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setObject(parameterIndex, x);
	}

	
	public boolean execute() throws SQLException {
		return doProfile(new ProfilePreparedStatementCallable<Boolean>() {
			
			public Boolean run(PreparedStatement statement) throws SQLException {
				return targetStatement.execute();
			}
		});
	}

	
	public void addBatch() throws SQLException {
		targetStatement.addBatch();
	}

	
	public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException {
		logContext.addParameterValue(parameterIndex, reader == null ? null : READER);//不处理流类型
		targetStatement.setCharacterStream(parameterIndex, reader, length);
	}

	
	public void setRef(int parameterIndex, Ref x) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setRef(parameterIndex, x);
	}

	
	public void setBlob(int parameterIndex, Blob x) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setBlob(parameterIndex, x);
	}

	
	public void setClob(int parameterIndex, Clob x) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setClob(parameterIndex, x);
	}

	
	public void setArray(int parameterIndex, Array x) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setArray(parameterIndex, x);
	}

	
	public ResultSetMetaData getMetaData() throws SQLException {
		return targetStatement.getMetaData();
	}

	
	public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setDate(parameterIndex, x, cal);
	}

	
	public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setTime(parameterIndex, x, cal);
	}

	
	public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setTimestamp(parameterIndex, x, cal);
	}

	
	public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException {
		logContext.addParameterValue(parameterIndex, null);
		targetStatement.setNull(parameterIndex, sqlType, typeName);
	}

	
	public void setURL(int parameterIndex, URL x) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setURL(parameterIndex, x);
	}

	
	public ParameterMetaData getParameterMetaData() throws SQLException {
		return targetStatement.getParameterMetaData();
	}

	
	public void setRowId(int parameterIndex, RowId x) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setRowId(parameterIndex, x);
	}

	
	public void setNString(int parameterIndex, String value) throws SQLException {
		logContext.addParameterValue(parameterIndex,value);
		targetStatement.setNString(parameterIndex, value);
	}

	
	public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException {
		logContext.addParameterValue(parameterIndex,value == null ? null : READER);//不处理
		targetStatement.setNCharacterStream(parameterIndex, value, length);
	}

	
	public void setNClob(int parameterIndex, NClob value) throws SQLException {
		logContext.addParameterValue(parameterIndex,value);
		targetStatement.setNClob(parameterIndex, value);
	}

	
	public void setClob(int parameterIndex, Reader reader, long length) throws SQLException {
		logContext.addParameterValue(parameterIndex,reader == null ? null : READER);//不处理
		targetStatement.setClob(parameterIndex, reader, length);
	}

	
	public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException {
		logContext.addParameterValue(parameterIndex,inputStream == null ? null : INPUTSTREAM);//不处理
		targetStatement.setBlob(parameterIndex, inputStream, length);
	}

	
	public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException {
		logContext.addParameterValue(parameterIndex,reader == null ? null : READER);//不处理
		targetStatement.setNClob(parameterIndex, reader, length);
	}

	
	public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException {
		logContext.addParameterValue(parameterIndex, xmlObject);
		targetStatement.setSQLXML(parameterIndex, xmlObject);
	}

	
	public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException {
		logContext.addParameterValue(parameterIndex, x);
		targetStatement.setObject(parameterIndex, x, targetSqlType, scaleOrLength);
	}

	
	public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException {
		logContext.addParameterValue(parameterIndex,x == null ? null : INPUTSTREAM);//不处理
		targetStatement.setAsciiStream(parameterIndex, x, length);
	}

	
	public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException {
		logContext.addParameterValue(parameterIndex,x == null ? null : INPUTSTREAM);//不处理
		targetStatement.setBinaryStream(parameterIndex, x, length);
	}

	
	public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException {
		logContext.addParameterValue(parameterIndex,reader == null ? null : READER);//不处理
		targetStatement.setCharacterStream(parameterIndex, reader, length);
	}

	
	public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException {
		logContext.addParameterValue(parameterIndex,x == null ? null : INPUTSTREAM);//不处理
		targetStatement.setAsciiStream(parameterIndex, x);
	}

	
	public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException {
		logContext.addParameterValue(parameterIndex,x == null ? null : INPUTSTREAM);//不处理
		targetStatement.setBinaryStream(parameterIndex, x);
	}

	
	public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException {
		logContext.addParameterValue(parameterIndex,reader == null ? null : READER);//不处理
		targetStatement.setCharacterStream(parameterIndex, reader);
	}

	
	public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException {
		logContext.addParameterValue(parameterIndex,value == null ? null : READER);//不处理
		targetStatement.setNCharacterStream(parameterIndex, value);
	}

	
	public void setClob(int parameterIndex, Reader reader) throws SQLException {
		logContext.addParameterValue(parameterIndex,reader == null ? null : READER);//不处理
		targetStatement.setClob(parameterIndex, reader);
	}

	
	public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException {
		logContext.addParameterValue(parameterIndex,inputStream == null ? null : INPUTSTREAM);//不处理
		targetStatement.setBlob(parameterIndex, inputStream);
	}

	
	public void setNClob(int parameterIndex, Reader reader) throws SQLException {
		logContext.addParameterValue(parameterIndex,reader == null ? null : READER);//不处理
		targetStatement.setNClob(parameterIndex, reader);
	}
	
	private <T> T doProfile(ProfilePreparedStatementCallable<T> profileCallable) throws SQLException{
		prepareLogContext();
		this.logContext.setType(JdbcLogContext.PREPARED_STATEMENT);
		T result;
		try {
			result = profileCallable.run(targetStatement);
			this.logContext.setEndTime(System.currentTimeMillis());
		} catch (SQLException e) {
			this.logContext.setException(e);
			throw e;
		}finally{
			jdbcProfiler.log(this.logContext);
		}
		return result;
	}
}
